/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.chain.shell;

import tal.drivechain.chain.Chain;
import tal.drivechain.chain.ChainNode;
import tal.drivechain.chain.FreePatcher;
import tal.drivechain.chain.Patcher;
import tal.drivechain.chain.RolePatcher;
import tal.drivechain.system.Globals;

/**
 *
 * @author eisental
 */
public class NodeObject extends ShellObject {

    public NodeObject(DriveShell shell) {
        super("node", "nodes", "node", shell);
    }

    @Override
    public boolean isActionSupported(Action action) {
        return (action!=Action.make && action!=Action.set);
    }

    @Override
    public void make(String command) throws IllegalArgumentException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void remove(String command) throws IllegalArgumentException {
        String nodeName = command;
        ChainNode n = Globals.findNode(nodeName, shell.getActiveChain());
        String parentPath = "";
        if (n.getParentChain()!=null) parentPath = " from chain " + n.getParentChain().getPath();

        n.destroy();
        
        out.println("Node " + n.getName() + " is removed" + parentPath + ".");
        n=null;
        System.gc();
    }

    public void start(String command) throws IllegalArgumentException {
        Globals.findChain(command, shell.getActiveChain()).start();
    }

    public void stop(String command) throws IllegalArgumentException {
        Globals.findChain(command, shell.getActiveChain()).stop();
    }

    public void reset(String command) throws IllegalArgumentException {
        ChainNode c = Globals.findNode(command, shell.getActiveChain());
        out.println("Clearing node " + c.getName() + ".");
        c.reset();
    }

    public void disconnect(String command) throws IllegalArgumentException {
        Patcher p = shell.getActiveChain().getPatcher();
        if (p==null || p instanceof FreePatcher) {
            //disconnect mod x from y
            String[] split = command.split(" from ");
            if (split.length==1) {
                ChainNode n = shell.getActiveChain().getNodeByPath(command);
                n.disconnect();
                out.println("Disconnected " + n.getName() + " from all other nodes.");
            } else if (split.length==2) {
                ChainNode a = shell.getActiveChain().getNodeByPath(split[0]);
                ChainNode b = shell.getActiveChain().getNodeByPath(split[1]);

                boolean foundIn = b.removeInput(a);
                boolean foundOut = b.removeOutput(a);
                if (foundOut) {
                    a.removeInput(b);
                } if (foundIn) {
                    a.removeOutput(b);
                }
                if (foundOut || foundIn)
                    out.println("Disconnected " + a.getName() + " from " + b.getName());
                else throw new IllegalArgumentException("Node " + a.getName() + " is not connected to node " + b.getName());
            } else throw new IllegalArgumentException("Invalid disconnect node syntax (should be: disconnect node a [from b] )");
        } else if (p instanceof RolePatcher) {
            //disconnect node x
            ChainNode n = Globals.findNode(command.trim(), shell.getActiveChain());
            n.disconnect();
            out.println("Disconnected " + n.getName() + " from the patch.");
        }
    }

    @Override
    public void set(String command) throws IllegalArgumentException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void list() throws IllegalArgumentException {
        if (shell.getActiveChain().getChildNodes().isEmpty()) out.println("Chain " + shell.getActiveChain().getPath() + " doesn't have any child nodes.");
        else {
            out.println("Child nodes of chain " + shell.getActiveChain().getPath() + ":");
            for (ChainNode n : shell.getActiveChain().getChildNodes().values())
                out.println("\t" + n.getName() + " (" + n.getNodeClassName() + ")");
        }
    }

    @Override
    public void inspect(String command) throws IllegalArgumentException {
        out.println(InfoPrinter.printNode(Globals.findNode(command, shell.getActiveChain())));
    }

    public void rename(String command) throws IllegalArgumentException {
        String[] split = command.split(" to ");
        if (split.length!=2)
            throw new IllegalArgumentException("Invalid syntax for rename node command (should be: rename node <a> to <b> )");

        String smod = split[0].trim();
        String sname = split[1].trim();
        ChainNode node = Globals.findNode(smod, shell.getActiveChain());
        node.getParentChain().renameChild(node, sname);
        node.setName(sname);
    }

    public void move(String command) throws IllegalArgumentException {
        String[] split = command.split(" to ");
        if (split.length!=2)
            throw new IllegalArgumentException("Invalid syntax for move chain command (should be: move chain <chain name> to <parent chain> )");
        ChainNode source = Globals.findNode(split[0], shell.getActiveChain());

        if (source.getInputs().size()>0 || source.getOutputs().size()>0)
            throw new IllegalArgumentException("Can't move node " + source.getPath() + ". It must be disconnected from other nodes first.");

        Chain newParent = Globals.findChain(split[1], shell.getActiveChain());

        Chain oldParent = source.getParentChain();

        source.setParentChain(newParent);
        newParent.addChild(source);
        oldParent.removeChild(source.getName());
        if (shell.getActiveChain()==source)
            shell.setActiveChain((Chain)source);
        out.println("Node " + source.getPath() + " is now a child of " + newParent.getName());
    }
}
